Type Console
	
	Const CONSOLE_WIDTH%  = (Graphics.GFX_WIDTH  / Graphics.FONT_SIZE)
	Const CONSOLE_HEIGHT% = (Graphics.GFX_HEIGHT / Graphics.FONT_SIZE) / 2

	Const CONSOLE_OPACITY# = 0.5

	Const CONSOLE_TEXT_COLOR_R% = 250
	Const CONSOLE_TEXT_COLOR_G% = 250
	Const CONSOLE_TEXT_COLOR_B% = 250
	
	Const CONSOLE_CHAT_COLOR_R% = 225
	Const CONSOLE_CHAT_COLOR_G% = 225
	Const CONSOLE_CHAT_COLOR_B% = 75
	
	Const CONSOLE_INPUT_COLOR_R% = 50
	Const CONSOLE_INPUT_COLOR_G% = 250
	Const CONSOLE_INPUT_COLOR_B% = 50
			
	Const ENABLE_DEBUG_LOG% = True
	
	Const CARET_INTERVAL% = 20
		
	Const INPUT_PREFIX$ = "> "
	Const INITIAL_TEXT$ = "Project F v0.1 Console - Type /? for a list of commands, ~~ to show/hide console"
	
	Global consoleDebugLog:TStream
	
	Global consoleText$[]
	Global consoleColor%[]
	
	Global clipboard$
	
	Global inputLog$[]
	Global inputLogPos%
	Global consoleInput$
	Global selectionStart%
	Global selectionEnd%
	
	Global consoleScroll%
	Global consoleOpen%
	Global newMessages%
	
	Global caret%
	
	Function Init%()
	
		consoleText  = [INITIAL_TEXT, "-------------------------------------------------------------------------------"]
		consoleColor = [(CONSOLE_TEXT_COLOR_R Shl 16) | (CONSOLE_TEXT_COLOR_G Shl 8) | (CONSOLE_TEXT_COLOR_B), (CONSOLE_TEXT_COLOR_R Shl 16) | (CONSOLE_TEXT_COLOR_G Shl 8) | (CONSOLE_TEXT_COLOR_B)]
		
		inputLog = [""]
		inputLogPos = 1
		
		consoleScroll = 0
		consoleOpen   = True
		
		newMessages = False
		
		clipboard$ = ""
		
		consoleInput$ = ""
		selectionStart = 0
		selectionEnd   = 0
		
		If ENABLE_DEBUG_LOG
		
			consoleDebugLog = WriteFile("debuglog.txt")
			
			If Not consoleDebugLog
			
				ConsolePrint("Error - Unable to open debug log")
				
			Else
			
				ConsolePrint("Logging enabled - 'debuglog.txt'")
				
			EndIf
			
		EndIf
		
		Return True
		
	End Function

	Function Update%()
	
		Local success% = True
		
		If KeyPressed(KEY_TILDE)
		
			consoleOpen = 1 - consoleOpen
			
			newMessages = False
			
			FlushKeys
			
		EndIf
	
		caret = caret - 1
		
		If caret <= -CARET_INTERVAL Then caret = CARET_INTERVAL
		
		If consoleOpen
				
			If KeyPressed(KEY_PAGEUP)
			
				If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
					
					consoleScroll = consoleScroll - CONSOLE_HEIGHT
					
				Else If KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)
				
					consoleScroll = 0
					
				Else
				
					consoleScroll = consoleScroll - 1
					
				EndIf
			
				If consoleScroll < 0 Then consoleScroll = 0	
				
				If Len(consoleText) < CONSOLE_HEIGHT Then consoleScroll = 0
				
			Else If KeyPressed(KEY_PAGEDOWN)
			
				If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
					
					consoleScroll = consoleScroll + CONSOLE_HEIGHT
					
				Else If KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)
				
					consoleScroll = (Len(consoleText) - CONSOLE_HEIGHT + 1)
					
				Else
				
					consoleScroll = consoleScroll + 1
					
				EndIf			
			
				If consoleScroll > (Len(consoleText) - CONSOLE_HEIGHT + 1) Then consoleScroll = (Len(consoleText) - CONSOLE_HEIGHT + 1)
			
				If Len(consoleText) < CONSOLE_HEIGHT Then consoleScroll = 0
						
			EndIf
			
			Local char% = GetChar()
			
			While char
			
				If TextWidth(Chr$(char)) > 0
				
					consoleInput$ = Mid$(consoleInput$, 1, selectionStart) + Chr$(char) + Mid$(consoleInput$, selectionEnd + 1, Len(consoleInput$) - selectionEnd)
				
					selectionStart = selectionStart + 1
					selectionEnd   = selectionStart
					
				EndIf
				
				char = GetChar()
				
			Wend
			
			If KeyPressed(KEY_X)
			
				If (KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)) And selectionStart <> selectionEnd
			
					clipboard$ = Mid$(consoleInput$, selectionStart + 1, selectionEnd - selectionStart)
				
					consoleInput$ = Mid$(consoleInput$, 1, selectionStart) + Mid$(consoleInput$, selectionEnd + 1, Len(consoleInput$) - selectionEnd)
					
					selectionStart = selectionStart + 1
					selectionEnd   = selectionStart
									
				EndIf
				
			Else If KeyPressed(KEY_C)
			
				If (KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)) And selectionStart <> selectionEnd
	
					clipboard$ = Mid$(consoleInput$, selectionStart + 1, selectionEnd - selectionStart)
							
				EndIf			
			
			EndIf
			
			If KeyPressed(KEY_V)
			
				If (KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)) And clipboard$ <> ""
				
					consoleInput$ = Mid$(consoleInput$, 1, selectionStart) + clipboard$ + Mid$(consoleInput$, selectionEnd + 1, Len(consoleInput$) - selectionEnd)
					
					selectionEnd   = selectionEnd + Len(clipboard$)
					selectionStart = selectionEnd
					
				EndIf
						
			EndIf
			
			If KeyPressed(KEY_BACKSPACE)
				
				If selectionEnd > 0
				
					If selectionStart = selectionEnd Then selectionStart = selectionEnd - 1
					
					consoleInput$ = Mid$(consoleInput$, 1, selectionStart) + Mid$(consoleInput$, selectionEnd + 1, Len(consoleInput$) - selectionEnd)
					
					selectionEnd   = selectionStart
				
				EndIf
		
			Else If KeyPressed(KEY_DELETE)
			
				If selectionStart < Len(consoleInput$)
				
					If selectionStart = selectionEnd Then selectionEnd = selectionStart + 1
					
					consoleInput$ = Mid$(consoleInput$, 1, selectionStart) + Mid$(consoleInput$, selectionEnd + 1, Len(consoleInput$) - selectionEnd)
					
					selectionEnd  = selectionStart
				
				EndIf
						
			EndIf
			
			If KeyPressed(KEY_LEFT)
			
				If KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)
				
					If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
						
						selectionStart = 0
				
					Else
				
						selectionStart = 0
						selectionEnd   = 0
				
					EndIf
					
				Else
				
					If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
						
						If selectionStart > 0 Then selectionStart = selectionStart - 1
				
					Else
				
						If selectionStart > 0 Then selectionStart = selectionStart - 1
						
						selectionEnd = selectionStart
				
					EndIf
				
				EndIf
				
				caret = CARET_INTERVAL
				
			Else If KeyPressed(KEY_RIGHT)
			
				If KeyDown(KEY_LCONTROL) Or KeyDown(KEY_RCONTROL)
				
					If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
						
						selectionEnd = Len(consoleInput$)
				
					Else
				
						selectionStart = Len(consoleInput$)
						selectionEnd   = selectionStart
				
					EndIf
					
				Else
				
					If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
						
						If selectionEnd < Len(consoleInput$) Then selectionEnd = selectionEnd + 1
				
					Else
				
						If selectionEnd < Len(consoleInput$) Then selectionEnd   = selectionEnd + 1
						
						selectionStart = selectionEnd
				
					EndIf
				
				EndIf			
			
				caret = CARET_INTERVAL
				
			EndIf
			
			If KeyPressed(KEY_UP)
			
				If inputLogPos > 0
				
					inputLogPos = inputLogPos - 1
					consoleInput$ = inputLog$[inputLogPos]
					
				EndIf
	
				If selectionStart > Len(consoleInput$) selectionStart = Len(consoleInput$)
				If selectionEnd   > Len(consoleInput$) selectionEnd   = Len(consoleInput$)
						
			Else If KeyPressed(KEY_DOWN)
			
				If inputLogPos < Len(inputLog) - 1
				
					inputLogPos = inputLogPos + 1
					consoleInput$ = inputLog$[inputLogPos]
					
				EndIf
				
				If selectionStart > Len(consoleInput$) selectionStart = Len(consoleInput$)
				If selectionEnd   > Len(consoleInput$) selectionEnd   = Len(consoleInput$)				
			
			EndIf
			
			If KeyPressed(KEY_HOME)
			
				If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
					
					selectionStart = 0
			
				Else
			
					selectionStart = 0
					selectionEnd   = 0
			
				EndIf			
		
				caret = CARET_INTERVAL
				
			Else If KeyPressed(KEY_END)
			
				If KeyDown(KEY_LSHIFT) Or KeyDown(KEY_RSHIFT)
					
					selectionEnd = Len(consoleInput$)
			
				Else
			
					selectionStart = Len(consoleInput$)
					selectionEnd   = selectionStart
			
				EndIf
				
				caret = CARET_INTERVAL
						
			EndIf
			
			If KeyPressed(KEY_ENTER)
			
				If Len(consoleInput$) > 0
				
					success = ConsoleExecute(consoleInput$)
					
					Local logInput% = False
					
					If inputLogPos = Len(inputLog)
					
						logInput = True
						
					Else
					
						If consoleInput$ <> inputLog$[inputLogPos]
						
							logInput = True
							
						EndIf
						
					EndIf
					
					If logInput
					
						inputLog = inputLog[..Len(inputLog) + 1]
						inputLog[Len(inputLog) - 1] = consoleInput$
						
					EndIf
					
					inputLogPos = Len(inputLog)
					
					consoleInput$ = ""
					
					selectionStart = 0
					selectionEnd   = 0
					
				EndIf
			
			EndIf
			
		EndIf
		
		Return success
			
	End Function

	Function Shutdown%()
	
		ConsolePrint("Shutting down console...")
		
		If ENABLE_DEBUG_LOG
		
			If consoleDebugLog
			
				CloseFile consoleDebugLog
				
			EndIf
			
		EndIf
		
		Return True
		
	End Function
	
	Function Draw()
		
		If consoleOpen
	
			SetTransform(0, 1.0, 1.0)
			
			SetBlend(ALPHABLEND)
			SetAlpha(CONSOLE_OPACITY#)
			
			SetColor(0, 0, 0)
			DrawRect(0, 0, Graphics.GFX_WIDTH, CONSOLE_HEIGHT * Graphics.FONT_SIZE)
	
			SetColor(CONSOLE_TEXT_COLOR_R, CONSOLE_TEXT_COLOR_G, CONSOLE_TEXT_COLOR_B)
			DrawRect(0, CONSOLE_HEIGHT * Graphics.FONT_SIZE, Graphics.GFX_WIDTH, 1)
			
			SetAlpha(1.0)
			
			For Local line% = 0 To CONSOLE_HEIGHT - 1
			
				Local consoleLine% = line + consoleScroll
				
				If consoleLine = Len(consoleText)
				
					SetColor(CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)	
					DrawText(INPUT_PREFIX$ + consoleInput$, 0, line * Graphics.FONT_SIZE)
					
					If selectionStart = selectionEnd
						
						If caret > 0 Then DrawRect(TextWidth(INPUT_PREFIX$) + TextWidth(Mid$(consoleInput$, 1, selectionEnd)), line * Graphics.FONT_SIZE, 1, Graphics.FONT_SIZE)
							
					Else
					
						Local startWidth% = TextWidth(Mid$(consoleInput$, 1, selectionStart))
						Local endWidth%   = TextWidth(Mid$(consoleInput$, 1, selectionEnd))
						
						DrawRect(TextWidth(INPUT_PREFIX$) + startWidth, line * Graphics.FONT_SIZE, (endWidth - startWidth), Graphics.FONT_SIZE)
						
						SetColor 0, 0, 0
						
						DrawText(Mid$(consoleInput$, selectionStart + 1, selectionEnd - selectionStart), TextWidth(INPUT_PREFIX$) + startWidth, line * Graphics.FONT_SIZE)
						
					EndIf
					
				Else If consoleLine >= 0 And consoleLine < Len(consoleText)
				
					SetColor((consoleColor[consoleLine] & $FF0000) Shr 16, (consoleColor[consoleLine] & $00FF00) Shr 8, (consoleColor[consoleLine] & $0000FF))	
					DrawText(consoleText$[consoleLine], 0, line * Graphics.FONT_SIZE)
					
				EndIf
			
			Next
			
		Else
		
			If newMessages
				
				If caret > 0
				
					SetTransform(0, 1.0, 1.0)
					
					SetBlend(ALPHABLEND)
					SetAlpha(CONSOLE_OPACITY#)
					
					SetColor((consoleColor[Len(consoleColor) - 1] & $FF0000) Shr 16, (consoleColor[Len(consoleColor) - 1] & $00FF00) Shr 8, (consoleColor[Len(consoleColor) - 1] & $0000FF))
					DrawRect(0, 0, Graphics.GFX_WIDTH, 3)
					
				EndIf
				
			EndIf
			
		EndIf
		
	End Function
	
	Function ConsolePrint(text$, r% = CONSOLE_TEXT_COLOR_R, g% = CONSOLE_TEXT_COLOR_G, b% = CONSOLE_TEXT_COLOR_B)
	
		If ENABLE_DEBUG_LOG
		
			If consoleDebugLog
			
				WriteLine(consoleDebugLog, text$)
				
				consoleDebugLog.Flush()
				
			EndIf
			
		EndIf
		
		consoleText = consoleText[..Len(consoleText) + 1]
		consoleText[Len(consoleText) - 1] = ""
		
		consoleColor = consoleColor[..Len(consoleColor) + 1]
		consoleColor[Len(consoleColor) - 1] = (r Shl 16) | (g Shl 8) | (b)
		
		ConsoleWrite(text$)
	
		consoleScroll = Len(consoleText) - CONSOLE_HEIGHT + 1
		If consoleScroll < 0 Then consoleScroll = 0
		
		If Not consoleOpen Then newMessages = True
		
	End Function

	Function ConsoleWrite(text$)
	
		consoleText[Len(consoleText) - 1] = consoleText[Len(consoleText) - 1] + text$
	
	End Function
	
	Function ConsoleExecute%(command$)
		
		Local tokens$[] = Tokenize(command$)
		
		Select Lower$(tokens$[0])
		
			Case "/?"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
				
				ConsolePrint("Command list:")
				
				ConsolePrint(" /?                                  - Prints this list of commands")
				ConsolePrint(" /debug                              - Stops on a debug breakpoint")
				ConsolePrint(" /name [player_name]                 - Shows or prints your player name")
				ConsolePrint(" /lansay message                     - Forces a chat message to broadcast to LAN")
				ConsolePrint(" /kick player_name                   - Forcefully disconnect a player")
				ConsolePrint(" /kickid player_id                   - Forcefully disconnect a player by player ID")
				ConsolePrint(" /maxplayers [new_max_players]       - Shows or changes the max players in the game")
				ConsolePrint(" /time                               - Prints the current time in millisecs")
				ConsolePrint(" /netstat                            - Prints network info")
				ConsolePrint(" /entitystat                         - Prints entity info")
				ConsolePrint(" /listsprites                        - Print list of loaded sprite resources")
				ConsolePrint(" /listsounds                         - Print list of loaded sound resources")			
				ConsolePrint(" /listsaves                          - Show existing saved games")
				ConsolePrint(" /removesave save_name               - Show existing saved games")
				ConsolePrint(" /listgames                          - Show available LAN games and players")
				ConsolePrint(" /hostgame [save_name] [max_players] - Starts a game with the specified save name and player limit")
				ConsolePrint(" /joingame ip_address                - Joins the game at the specified host")
				ConsolePrint(" /leavegame                          - Disconnect from the current game")
				ConsolePrint(" /quit                               - Exits the application")
			
			Case "/debug"
			
				DebugStop
				
			Case "/kick"
			
				If Len(tokens) <> 2
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				Else
					
					Local kickedClient:NetClient = Null
					
					For Local client:NetClient = EachIn Network.clientList
						
						If client.playerName$ = tokens[1]
						
							kickedClient = client
							Exit
							
						EndIf
						
					Next
					
					If kickedClient = Null
					
						ConsolePrint("Error - No player by that name found")
						
					Else
											
						Console.ConsolePrint("Kicked '" + kickedClient.playerName$ + "'")
						
						Network.DisconnectClient(kickedClient)
						
					EndIf
					
				EndIf
									
			Case "/kickid"
			
				If Len(tokens) <> 2
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				Else
					
					Local kickedClient:NetClient = Null
					
					For Local client:NetClient = EachIn Network.clientList
						
						If client.playerID = tokens[1].ToInt()
						
							kickedClient = client
							Exit
							
						EndIf
						
					Next
					
					If kickedClient = Null
					
						ConsolePrint("Error - No player with that ID found")
						
					Else
											
						Console.ConsolePrint("Kicked '" + kickedClient.playerName$ + "'")
						
						Network.DisconnectClient(kickedClient)
						
					EndIf
					
				EndIf
							
			Case "/maxplayers"
				
				If Len(tokens) = 1
				
					ConsolePrint("Max players: " + String(Network.maxPlayers))
					
				Else If Len(tokens) = 2
				
					Local maxPlayers% = tokens[1].ToInt()
					
					If maxPlayers < 1 Or maxPlayers > 255
					
						ConsolePrint("Error - Invalid number of players")
						
					Else
						
						Network.maxPlayers = maxPlayers
						
						ConsolePrint("Max players: " + String(Network.maxPlayers))
						
					EndIf
					
				Else

					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				EndIf
												
			Case "/name"
				
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
				
				If Len(tokens) = 1
				
					ConsolePrint("Name: " + Game.playerName$)
					
				Else If Len(tokens) = 2
				
					If Network.netState = Network.STATE_OFFLINE
					
						If Len(tokens[1]) > Game.PLAYER_NAME_LENGTH Or Len(tokens[1]) < 1
						
							ConsolePrint("Error - Invalid name length")
							
						Else
						
							Game.playerName$ = tokens[1]
							ConsolePrint("Name: " + Game.playerName$)
							
						EndIf
						
					Else
					
						ConsolePrint("Error - You must be offline to change your name")
						
					EndIf
					
				Else
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				EndIf
				
			Case "/entitystat"
	
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
	
				ConsolePrint("Total Entity Count: " + String(Game.entityList.Count()))
				ConsolePrint("Net Entities:")
				
				For Local myEntity:NetEntity = EachIn Game.entityList
				
					ConsolePrint("EntityID: " + String(myEntity.entityID))
					ConsolePrint("Entity Type ID: " + String(myEntity.typeIndex) + "(" + Game.types[myEntity.typeIndex].Name$() + ")")
					ConsolePrint("")
					
				Next
				
			Case "/time"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				ConsolePrint("Time: " + System.frameTime)
				
			Case "/netstat"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				If Network.netState = Network.STATE_OFFLINE
				
					ConsolePrint("Net State: Offline")
					
				Else If Network.netState = Network.STATE_CONNECTING
				
					ConsolePrint("Net State: Connecting")
	
				Else If Network.netState = Network.STATE_CLIENT
				
					ConsolePrint("Net State: Client")
									
				Else If Network.netState = Network.STATE_SERVER
				
					ConsolePrint("Net State: Server")
					
				EndIf
				
				Local localIPs$ = ""
				
				For Local LocalIp% = EachIn Network.localIPs
				
					localIPs$ = localIPs$ + DottedIP$(LocalIp) + ", "	
				
				Next
				
				ConsolePrint("Local IPs: " + Left$(localIPs$, Len(localIPs$) - 2))
				
				Local avgBytesIn% = 0
				
				If Network.totalPacketsIn > 0 Then avgBytesIn = Network.totalBytesIn / Network.totalPacketsIn
	
				Local avgBytesOut% = 0
				
				If Network.totalPacketsOut > 0 Then avgBytesOut = Network.totalBytesOut / Network.totalPacketsOut
				
				Local bandwidthIn%  = (1000 / Network.UPDATE_INTERVAL) * avgBytesIn
				Local bandwidthOut% = (1000 / Network.UPDATE_INTERVAL) * avgBytesOut
				
				ConsolePrint("Last Sent Update Time: " + String(Network.lastStateTime))
				ConsolePrint("Bytes Received: " + String(Network.totalBytesIn))
				ConsolePrint("Bytes Sent: " + String(Network.totalBytesOut))
				ConsolePrint("Avg Bytes Received: " + String(avgBytesIn))
				ConsolePrint("Avg Bytes Sent: " + String(avgBytesOut))
				ConsolePrint("Inbound Bandwidth: " + String(bandwidthIn) + " bytes/sec")
				ConsolePrint("Outbound Bandwidth: " + String(bandwidthOut) + " bytes/sec")			
				ConsolePrint("Packets Received: " + String(Network.totalPacketsIn))
				ConsolePrint("Packets Sent: " + String(Network.totalPacketsOut))
				ConsolePrint("Inbound Packets Dropped: " + String(Network.totalPacketsInDropped))
				ConsolePrint("Outbound Packets Dropped: " + String(Network.totalPacketsOutDropped))
				
				ConsolePrint("")
				
				For Local client:NetClient = EachIn Network.clientList
			
					ConsolePrintClientInfo(client)
							
				Next	
				
			Case "/listsprites"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				ConsolePrint("Loaded sprite resources:")
			
				For Local mySpriteResource:SpriteResource = EachIn Graphics.spriteResources
				
					ConsolePrint("Sprite: " + mySpriteResource.path$)	
					ConsolePrint("Dimensions: " + String(ImageWidth(mySpriteResource.image)) + " x " + String(ImageHeight(mySpriteResource.image)))
	
					For Local mySpriteAnimation:SpriteAnimation = EachIn mySpriteResource.animations
					
						Local animString$ = "Anim '" + mySpriteAnimation.name$ + "' (Loop=" + String(mySpriteAnimation.loopFrame) + "): ["
						
						For Local f% = 0 To Len(mySpriteAnimation.frames) - 1
						
							animString$ = animString$ + String(mySpriteAnimation.frames[f])
							If f <> Len(mySpriteAnimation.frames) - 1 Then animString$ = animString$ + ","
							
						Next
						
						animString$ = animString$ + "]"
						
						ConsolePrint(animString$)
						
					Next
					
					ConsolePrint("")
					
				Next
						
			Case "/listsounds"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				ConsolePrint("Loaded sound resources:")
			
				For Local mySoundResource:SoundResource = EachIn Audio.soundResources
				
					ConsolePrint(" " + mySoundResource.path$)
					
				Next
						
			Case "/listsaves"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				ConsolePrint("Saved game list:")
			
				For Local save$ = EachIn Game.saves
				
					ConsolePrint(" " + save$)
					
				Next
			
			Case "/removesave"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				If Len(tokens) <> 2
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				Else
				
					Local fileName$ = "saves\" + tokens[1] + ".sav"
					
					If DeleteFile(fileName$)
					
						ConsolePrint("Saved game '" + tokens[1] + "' deleted")
						
						Game.saves.Remove(tokens[1])
						
					Else
					
						ConsolePrint("Error removing saved game '" + tokens[1] + "'")
						
					EndIf
				
				EndIf
							
			Case "/listgames"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				ConsolePrint("Searching for games...")
				
				Network.RefreshGameList()
			
			Case "/hostgame"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				If Len(tokens) > 3 Or Len(tokens) < 1
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				Else
				
					If Network.netState <> Network.STATE_OFFLINE
					
						ConsolePrint("Error - Game already in progress")
						
					Else
						
						Local _saveName$
						
						If Len(tokens) = 1
						
							_saveName$ = ""
							
						Else
						
							_saveName$ = tokens[1]
							
						EndIf
						
						If Len(tokens) < 3
						
							ConsolePrint("Starting game...")
							Network.HostGame(_saveName$)
							
						Else
							
							Local maxPlayers% = tokens[2].ToInt()
							
							If (maxPlayers < 1 Or maxPlayers > 255)
							
								ConsolePrint("Error - Invalid number of players")
								
							Else
							
								ConsolePrint("Starting game...")
								
								Network.HostGame(_saveName$, maxPlayers)
								
							EndIf
							
						EndIf
						
					EndIf
					
				EndIf	
			
			Case "/joingame"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				If Len(tokens) <> 2
				
					ConsolePrint("Invalid number of parameters for command '" + tokens$[0] + "'")
					
				Else
				
					If Network.netState = Network.STATE_OFFLINE
						
						ConsolePrint("Connecting to host '" + tokens[1] + "'...")
						
						Network.JoinGame(tokens[1])
						
					Else
					
						ConsolePrint("Error - Game already in progress")
						
					EndIf
					
				EndIf		
			
			Case "/leavegame"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
						
				If Network.netState = Network.STATE_OFFLINE
				
					ConsolePrint("Error - No game in progress")
					
				Else
				
					Network.LeaveGame()
					
					ConsolePrint("Disconnected.")
					
				EndIf		
		
			Case "/quit"
			
				ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
				
				Network.LeaveGame()
					
				Return False
			
			Case "/lansay"
				
				Network.SendChat(Game.playerName$, Right$(command$, Len(command$) - 8), True)

				Return True
	
								
			Default
				
				If Left$(tokens[0], 1) = "/"
				
					ConsolePrint(INPUT_PREFIX$ + command$, CONSOLE_INPUT_COLOR_R, CONSOLE_INPUT_COLOR_G, CONSOLE_INPUT_COLOR_B)
							
					ConsolePrint("Unknown command - '" + tokens$[0] + "'")
					
				Else
				
					Network.SendChat(Game.playerName$, command$)
				
					Return True
					
				EndIf
				
		End Select
		
		ConsolePrint("")
	
		Return True
		
	End Function
		
	Function ConsolePrintClientInfo(client:NetClient)
	
		Local avgBytesIn% = 0
		
		If client.packetsIn > 0 Then avgBytesIn = client.bytesIn / client.packetsIn
	
		Local avgBytesOut% = 0
		
		If client.packetsOut > 0 Then avgBytesOut = client.bytesOut / client.packetsOut
		
		Local bandwidthIn%  = (1000 / Network.UPDATE_INTERVAL) * avgBytesIn
		Local bandwidthOut% = (1000 / Network.UPDATE_INTERVAL) * avgBytesOut
			
		If Network.netState = Network.STATE_SERVER
		
			ConsolePrint("Client IP: " + DottedIP$(client.IP))
			
		Else
		
			ConsolePrint("Server IP: " + DottedIP$(client.IP))
			
		EndIf
		
		Local lastAckedSeq%     = 0
		
		If client.receivedPackets.Count() > 0
		
			lastAckedSeq = NetPacket(client.receivedPackets.Last()).thisSeq
			
		EndIf
		
		ConsolePrint("Player Name: " + client.playerName$)
		ConsolePrint("Player ID: " + String(client.playerID))
		ConsolePrint("Last Acked Seq: " + String(lastAckedSeq))
		ConsolePrint("Last Received Time: " + String(client.lastReceivedTime))					
		ConsolePrint("Bytes Received: " + String(client.bytesIn))
		ConsolePrint("Bytes Sent: " + String(client.bytesOut))
		ConsolePrint("Avg Bytes Received: " + String(avgBytesIn))
		ConsolePrint("Avg Bytes Sent: " + String(avgBytesOut))
		ConsolePrint("Inbound Bandwidth: " + String(bandwidthIn) + " bytes/sec")
		ConsolePrint("Outbound Bandwidth: " + String(bandwidthOut) + " bytes/sec")			
		ConsolePrint("Packets Received: " + String(client.packetsIn))
		ConsolePrint("Packets Sent: " + String(client.packetsOut))
		ConsolePrint("Inbound Packets Dropped: " + String(client.packetsInDropped))
		ConsolePrint("Outbound Packets Dropped: " + String(client.packetsOutDropped))
		ConsolePrint("")
		
	End Function

End Type